package com.autumn.web;

import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.Banner;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.web.HttpMessageConverters;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.annotation.Order;
import org.springframework.format.FormatterRegistry;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.util.AntPathMatcher;
import org.springframework.validation.MessageCodesResolver;
import org.springframework.validation.Validator;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.config.annotation.AsyncSupportConfigurer;
import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.PathMatchConfigurer;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import com.autumn.auditing.IClientInfoProvider;
import com.autumn.runtime.session.IAutumnSession;
import com.autumn.runtime.session.NullAutumnSession;
import com.autumn.spring.boot.properties.AutumnWebProperties;
import com.autumn.util.json.JsonUtils;
import com.autumn.web.auditing.WebClientInfoProvider;
import com.autumn.web.exception.filter.WebExceptionFilter;

/**
 * Web AutumnApplication
 * 
 * @author 老码农
 *
 *         2017-11-22 17:49:57
 */
@Configuration
@Order(100)
@EnableConfigurationProperties(AutumnWebProperties.class)
public abstract class AbstractAutumnApplication implements WebMvcConfigurer {

	/**
	 * 日志
	 */
	protected final Log logger = LogFactory.getLog(this.getClass());

	/**
	*
	*/
	public AbstractAutumnApplication() {
		logger.info("正在初始化 " + this.getClass());
		JsonUtils.initialize();
		JSON.DEFFAULT_DATE_FORMAT = this.getJsonDateDefaultFormat();
	}

	/**
	 * 运行 Spring Boot
	 * 
	 * @param applicationClass
	 *            应用类型
	 * @param args
	 *            参数
	 */
	public static void run(Class<? extends AbstractAutumnApplication> applicationClass, String[] args) {
		run(applicationClass, Banner.Mode.OFF, args);
	}

	/**
	 * 运行 Spring Boot
	 * 
	 * @param applicationClass
	 *            应用类型
	 * @param mode
	 *            模式
	 * @param args
	 *            参数集合
	 *
	 */
	public static void run(Class<? extends AbstractAutumnApplication> applicationClass, Banner.Mode mode,
			String[] args) {
		if (mode == null) {
			mode = Banner.Mode.CONSOLE;
		}
		SpringApplicationBuilder app = new SpringApplicationBuilder(applicationClass);
		app.bannerMode(mode).run(args);
	}

	/**
	 * 获取日期默认格式
	 *
	 * @return
	 */
	public String getJsonDateDefaultFormat() {
		return JsonUtils.JSON_DEFAULT_FORMAT;
	}

	@Autowired
	private AutumnWebProperties webConfigurationProperties;

	/**
	 * 获取 Web 配置属性
	 * 
	 * @return
	 */
	public final AutumnWebProperties getWebConfigurationProperties() {
		return webConfigurationProperties;
	}

	/**
	 * 是否是发布
	 * 
	 * @return
	 */
	public boolean isRelease() {
		return webConfigurationProperties != null && webConfigurationProperties.isRelease();
	}

	/**
	 * 获取序列化格式
	 *
	 * @return
	 */
	public SerializerFeature[] getSerializerFeatures() {
		if (isRelease()) {
			return JsonUtils.SERIALIZER_FEATURE_STANDARD;
		}
		return JsonUtils.SERIALIZER_FEATURE_PRETTYFORMAT;
	}

	/**
	 * 客户端信息驱动
	 *
	 * @return
	 */
	@Bean
	@Primary
	public IClientInfoProvider clientInfoProvider() {
		return new WebClientInfoProvider();
	}

	/**
	 * 
	 * @return
	 */
	@Bean
	@ConditionalOnMissingBean(WebExceptionFilter.class)
	public WebExceptionFilter webExceptionFilter() {
		return new WebExceptionFilter();
	}

	/**
	 * 会话
	 *
	 * @return
	 */
	@Bean
	@Primary
	@ConditionalOnMissingBean(IAutumnSession.class)
	public IAutumnSession autumnSession() {
		return new NullAutumnSession();
	}

	private CorsConfiguration buildConfig() {
		CorsConfiguration corsConfiguration = new CorsConfiguration();
		corsConfiguration.setAllowCredentials(true);
		corsConfiguration.addAllowedOrigin("*");
		corsConfiguration.addAllowedHeader("*");
		corsConfiguration.addAllowedMethod("*");
		return corsConfiguration;
	}

	/**
	 * 跨域
	 * 
	 * @return
	 */
	@Bean
	public FilterRegistrationBean corsFilter() {
		UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
		source.registerCorsConfiguration("/**", buildConfig());
		FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
		bean.setOrder(0);
		return bean;
	}

	@Bean
	@Primary
	public StringHttpMessageConverter stringHttpMessageConverter() {
		StringHttpMessageConverter converter = new StringHttpMessageConverter(StandardCharsets.UTF_8);
		return converter;
	}

	@Bean
	@Primary
	public HttpMessageConverter<Object> fastJsonHttpMessageConverter() {
		FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
		FastJsonConfig fastJsonConfig = new FastJsonConfig();
		fastJsonConfig.setSerializerFeatures(getSerializerFeatures());
		List<MediaType> mediaTypes = new ArrayList<>();
		mediaTypes.add(MediaType.APPLICATION_JSON_UTF8);
		fastConverter.setSupportedMediaTypes(mediaTypes);
		fastConverter.setFastJsonConfig(fastJsonConfig);
		return fastConverter;
	}

	@Bean
	@Primary
	public HttpMessageConverters fastJsonHttpMessageConverters() {
		return new HttpMessageConverters(this.fastJsonHttpMessageConverter(), this.stringHttpMessageConverter());
	}

	@Override
	public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
		converters.add(this.fastJsonHttpMessageConverter());
	}

	/**
	 * 不区分大小写
	 */
	@Override
	public void configurePathMatch(PathMatchConfigurer configurer) {
		AntPathMatcher matcher = new AntPathMatcher();
		matcher.setCaseSensitive(false);
		configurer.setPathMatcher(matcher);
	}

	@Override
	public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {

	}

	@Override
	public void configureAsyncSupport(AsyncSupportConfigurer configurer) {

	}

	@Override
	public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {

	}

	@Override
	public void addFormatters(FormatterRegistry registry) {

	}

	@Override
	public void addInterceptors(InterceptorRegistry registry) {

	}

	@Override
	public void addResourceHandlers(ResourceHandlerRegistry registry) {

	}

	@Override
	public void addCorsMappings(CorsRegistry registry) {

	}

	@Override
	public void addViewControllers(ViewControllerRegistry registry) {

	}

	@Override
	public void configureViewResolvers(ViewResolverRegistry registry) {

	}

	@Override
	public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {

	}

	@Override
	public void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> returnValueHandlers) {

	}

	@Override
	public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {

	}

	@Override
	public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {

	}

	@Override
	public void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {

	}

	@Override
	public Validator getValidator() {
		return null;
	}

	@Override
	public MessageCodesResolver getMessageCodesResolver() {
		return null;
	}
}
